package com.flying.ouyu.net;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.flying.client.network.NetworkProvider;
import com.flying.client.network.msg.OWMsg;
import com.flying.client.utils.Logger;

public class NetworkProxy {
	private static final Logger logger = Logger.getLogger(NetworkProxy.class.getName()); 
	
	private static Object _instanceLocker = new Object();
	private static NetworkProxy _instance = null;
	
	public static NetworkProxy getInstance()
	{
		if (_instance != null)
			return _instance;
		
		synchronized(_instanceLocker)
		{
			if (_instance == null)
			{
				_instance = new NetworkProxy();
			}
			
			return _instance;
		}
	}
	
	/**
	 * 等待写入的消息队列
	 */
	private BlockingQueue<OWMsg> waitMsgQueue = new LinkedBlockingQueue<OWMsg>();
	/**
	 * 消息队列锁
	 */
	private Object msgQueueLocker = new Object();
	
	private NetworkProvider netProvider = null;
	private NetworkSink netSink = null;
	
	/**
	 * 写数据线程
	 */
	private Thread writer = null;
	/**
	 * 超时监控线程
	 */
	private Thread timeoutMonitor = null;
	/**
	 * 等待反馈列表锁
	 */
	private Object feedbackMsgLocker = new Object();
	/**
	 * 等待反馈列表
	 */
	private List<OWMsg> feedbackMsgList = new ArrayList<OWMsg>();
	
	private NetworkProxy()
	{
		netSink = new NetworkSink();
		netProvider = new NetworkProvider(netSink);
		
		writer = new Thread(new MsgWriter());
		writer.start();
		
		timeoutMonitor = new Thread(new MsgTimeoutMonitor());
		timeoutMonitor.start();
	}
	
	/**
	 * 初始化网络模块
	 */
	public void init()
	{
		//TODO:init the network
		netProvider.addServerInfo("192.168.0.123", 8054);
		
		netSink.initMsgType();
		
		netProvider.connect();
	}
	/**
	 * 发送消息
	 * @param msg
	 */
	public void sendMsg(OWMsg msg)
	{
		netProvider.send(msg);
	}
	/**
	 * 暂停
	 */
	public void pause()
	{
		netProvider.pause();
	}
	/**
	 * 开始
	 */
	public void start()
	{
		netProvider.start();
	}
	/**
	 * 发送消息
	 * @param msg
	 */
	public void send(OWMsg msg)
	{
		synchronized(msgQueueLocker)
		{
			boolean flag = waitMsgQueue.offer(msg);
			msgQueueLocker.notify();
		}
		
		netProvider.send(msg);
	}
	
	private boolean isRuning()
	{
		return netProvider.isRuning();
	}
	
	private boolean isPaused()
	{
		return netProvider.isPaused();
	}
	/**
	 * 消息写入线程
	 * @author ufostop
	 *
	 */
 	class MsgWriter implements Runnable
	{
		public static final int CONN_ERROR_SLEEP_MILLS = 1 * 1000;
		@Override
		public void run() {
			while(true)
			{
				try
				{
					OWMsg msg = null;
					
					synchronized(msgQueueLocker)
					{
						//TODO:如果当前正在运行，而且不可读就关闭网络，再重新连接
						if (netProvider.isRuning() && !netProvider.canWrite())
						{
							netProvider.close();
							netProvider.connect();
							continue;
						}
						
						try{
							msg = waitMsgQueue.element();
						}
						catch(NoSuchElementException e)
						{
							msgQueueLocker.wait();
							continue;
						}
						
						if (msg == null)
							return;
						
						logger.debug("writer msg="+msg.getMsgSeq()+" "+ msg.getMsgType());
						
						//如果已经无效, 从队列中，删除该消息
						if (!msg.isEnable())
						{
							waitMsgQueue.remove(msg);
							continue;
						}
					}
					
					
					
					//如果需要反馈信息，就加入到等待反馈列表中。
					if (msg.isNeedFeedback())
					{
						synchronized(feedbackMsgLocker)
						{
							msg.setSendTime(Calendar.getInstance().getTimeInMillis());
							feedbackMsgList.add(msg);
							feedbackMsgLocker.notify();
						}
					}
					
					//TODO:条件具备了，就发送！,这里需要考虑是否需要加个锁？
					netProvider.send(msg);
				}
				catch(Throwable throwable)
				{
					logger.error("NetworkWriter Error="+throwable);
				}
			}
		}
	}
 	
 	/**
	 * 消息超时监控
	 * @author ufostop
	 */
	class MsgTimeoutMonitor implements Runnable
	{
		public void run()
		{
			while(true)
			{
				try
				{
					ArrayList<OWMsg> tmpMsgList = new ArrayList<OWMsg>();
					synchronized(feedbackMsgLocker)
					{
						if (feedbackMsgList.size() <= 0)
						{
							feedbackMsgLocker.wait();
						}
						
						for(int i = 0;i<feedbackMsgList.size();i++)
						{
							tmpMsgList.add(feedbackMsgList.get(i));
						}
					}
					long curTimeMills = Calendar.getInstance().getTimeInMillis();
					for(int i = 0;i<tmpMsgList.size();i++)
					{
						OWMsg msg = tmpMsgList.get(i);

						logger.debug("msg.sendtime = "+msg.getSendTime());
						if (msg.isTimeout(curTimeMills))
						{
							synchronized(feedbackMsgLocker)
							{
								feedbackMsgList.remove(msg);
							}
							
							msg.onTimeout();
						}
					}
					Thread.sleep(1000);
				}
				catch(Throwable throwable)
				{
					logger.error("MsgTimeoutMonitor Error="+throwable);
				}
			}
		}
	}
}
